package com.yqb.study.modular.controller.data;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.plugins.Page;
import com.yqb.study.common.controller.BaseController;
import com.yqb.study.common.pagination.PageFactory;
import com.yqb.study.common.pagination.PageInfoRspBT;
import com.yqb.study.common.session.IRedisSession;
import com.yqb.study.config.multidatasource.ClusterDataSourceProperties;
import com.yqb.study.config.multidatasource.MasterDataSourceProperties;
import com.yqb.study.constant.CodeMsgEnum;
import com.yqb.study.constant.cache.impl.DictFactory;
import com.yqb.study.constant.multidatasource.DataSourceEnum;
import com.yqb.study.modular.dao.mongdb.CustomerMongoDao;
import com.yqb.study.modular.dto.Customer;
import com.yqb.study.modular.persistence.model.City;
import com.yqb.study.modular.service.ICityService;
import com.yqb.study.modular.service.ISecKillService;
import com.yqb.study.modular.service.IUserService;
import com.yqb.study.modular.warpper.CityWarpper;
import com.yqb.study.support.HttpKit;
import com.yqb.study.util.ResultVoUtil;

import lombok.extern.slf4j.Slf4j;

// @RestController方法统一返回json报文
@RestController
@Slf4j
public class HelloWorldController extends BaseController {
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private CustomerMongoDao repository;	
    @Autowired
    private MasterDataSourceProperties masterDataSourceProperties;   
    @Autowired
    private ClusterDataSourceProperties clusterDataSourceProperties;   
    @Autowired
    private ICityService cityService;
    @Autowired
    private IUserService userService;    
    @Autowired
    private ISecKillService secKillService;
	
    // 测试微服务访问和日志级别、日志输出控制
	@GetMapping("/hello")
	public String helloWorld() {
		log.info("HelloWorldController  log.info");
		log.info("HelloWorldController  log.info");
		log.error("HelloWorldController  log.error");
		
		return "hello world!";
	}
	
	// 测试使用redis
	@GetMapping("/helloRedis")
	public String helloRedis() {
		stringRedisTemplate.opsForValue().set("word", "hello redis");
		
		log.info("Redis服务器变量【word】值是：" + stringRedisTemplate.opsForValue().get("word"));
		
		return "hello redis!";
	}	
	
	// 测试使用mongdb
	@GetMapping("/helloMongdb")
	public String helloMongdb() {
        repository.deleteAll();

        // save a couple of customers
        repository.save(new Customer("Alice", "Smith"));
        repository.save(new Customer("Bob", "Smith"));

        // fetch all customers
        log.info("Customers found with findAll():");
        log.info("-------------------------------");
        for (Customer customer : repository.findAll()) {
            log.info(customer.toString());
        }

        // fetch an individual customer
        log.info("Customer found with findByFirstName('Alice'):");
        log.info("--------------------------------");
        log.info(repository.findByFirstName("Alice").toString());

        log.info("Customers found with findByLastName('Smith'):");
        log.info("--------------------------------");
        for (Customer customer : repository.findByLastName("Smith")) {
            log.info(customer.toString());
        }
		
		return "hello mongdb!";
	}	
	
	// 测试从application.yml读取需要的参数
	@GetMapping("/helloConfig")
	public String helloConfig() {
		
		log.info("配置文件中druid中Master库名字是：" + masterDataSourceProperties.getName());
		log.info("配置文件中druid中Master库url是：" + masterDataSourceProperties.getUrl());
		
		log.info("配置文件中druid中Cluster库名字是：" + clusterDataSourceProperties.getName());
		log.info("配置文件中druid中Cluster库url是：" + clusterDataSourceProperties.getUrl());

		return "hello config!";
	}	
	
	// 测试使用多数据源切换，需要配置文件打开多数据源配置使用
	@GetMapping("/helloMultiDataSource")
	public String helloMultiDataSource() {
		
		// 没有使用DataSource注解
		log.info("没有使用DataSource注解-----数据源是：" + DataSourceEnum.MASTERDB.getNameEn());
		cityService.getAllCityInfo();
		
		// 使用DataSource注解指定使用Cluster
		log.info("使用DataSource注解指定使用Cluster-----数据源是：" + DataSourceEnum.CLUSTERDB.getNameEn());
		cityService.getAllCityInfoFromClusterDb();
		
		// 使用DataSource注解指定使用Master
		log.info("使用DataSource注解指定使用Master-----数据源是：" + DataSourceEnum.MASTERDB.getNameEn());
		cityService.getAllCityInfoFromMasterDb();
		
		return "hello multiDataSource!";
	}	
	
	// 检查mybatis-plus事务
	@GetMapping("/helloTransaction")
	public String helloTransaction() {	
		City cityItem4 = new City();
		cityItem4.setProvinceId("4");
		cityItem4.setCityName("事务4");
		cityItem4.setDescription("检查mybatis-plus事务4");
		
		City cityItem5 = new City();
		cityItem5.setCityName("事务5");
		cityItem5.setDescription("检查mybatis-plus事务5");		
		
		List<City> cityList = new ArrayList<>();
		cityList.add(cityItem4);
		cityList.add(cityItem5);
		
		// Master库因为有事务，所以没有provinceId为4
		try {
			cityService.saveCityListInMasterDb(cityList);
		} catch (Exception e) {
			log.error("Master库插入数据出错");
		}
		
		// Cluster库因为没有事务，插入第二条的时候会报错，但是库中应该有一条provinceId为4的数据
		try {
			cityService.saveCityListInClusterDb(cityList);
		} catch (Exception e) {
			log.error("Cluster库插入数据出错");
		}		
		
		return "hello transaction!";
	}
	
	// 检查分页
	@GetMapping("/helloPage")
	public Object helloPage() {
//		// City指的是返回的每条记录类型是City
//		// 方法defaultPage是在page对象中存放请求的limit、offset、sort、order参数
//		Page<City> page = new PageFactory<City>().defaultPage(); 
//		// 约定的搜索条件
//		Map<String, String> searchCond = HttpKit.getRequestParameters();
//		
//		List<City> cityList = cityService.getPageCityInfoFromClusterDb(page, searchCond);
//		
//		log.info("查询参数是：" + searchCond.toString());
//		log.info("查询结果是：" + cityList.toString());
		
		// Page泛型指的是每条记录查出来的类型
		// 方法defaultPage是在page对象中存放请求的limit、offset、sort、order参数
		Page<Map<String, Object>> page = new PageFactory<Map<String, Object>>().defaultPage(); 
		// 约定的搜索条件
		Map<String, String> searchCond = HttpKit.getRequestParameters();
		
		List<Map<String, Object>> cityInfoMapList = cityService.getPageCityInfoMapFromClusterDb(page, searchCond);
		
		log.info("查询参数是：" + searchCond.toString());
		log.info("查询结果是：" + cityInfoMapList.toString());	
		
		// 查询结果包装
		page.setRecords((List<Map<String, Object>>) new CityWarpper(cityInfoMapList).warp());
		
		// 通用返回包装
		PageInfoRspBT<Map<String, Object>> pageInfoRspBT = super.packForBT(page);
		return ResultVoUtil.success(CodeMsgEnum.QUERY_SUCCESS, pageInfoRspBT);
		
		// 如果是直接返回给Bootstrap Table使用
		// return super.packForBT(page);
	}
	
	// 测试使用redis缓存数据
	@GetMapping("/helloCache")
	public String helloCache() {
		
		log.info("字典查询结果：" + DictFactory.me().getNum2NameDicts("性别").toString());
		
		log.info("字典查询结果：" + DictFactory.me().getDictsList("性别").toString());
		
		
		// DictFactory.me().delDictsCache();
		
		return "hello cache!";
	}	
	
	// 将某个类的bean对象存入redis中并设置过期时间
	@GetMapping("/helloRedisBean")
	public String helloRedisBean() {
		City city = new City();
		city.setId(66);
		city.setProvinceId("8");
		city.setCityName("测试redis存bean对象");
		city.setDescription("测试redis存bean对象");
		
//		cityRedisDao.set(CityRedisKey.cityBean, "id_66", city);
//		
//		log.info(cityRedisDao.get(CityRedisKey.cityBean, "id_66").toString());
//		
//		if (cityRedisDao.exists(CityRedisKey.cityBean, "id_66")) {
//			log.info("存在id为66的city bean对象");
//		}
 
		return "hello redis bean!";
	}
	
	// 测试返回ResultVo
	@GetMapping("/helloReturn")
	public Object helloReturn() {
		return ResultVoUtil.error(CodeMsgEnum.SERVER_ERROR);
	}
	
    // 测试Redis Session 
	@GetMapping("/helloSession")
	public Object helloSession(IRedisSession sessionRedis) {
		
		City city = new City();
		city.setId(66);
		city.setProvinceId("8");
		city.setCityName(sessionRedis.getSessionRedis().getToken());
		city.setDescription(sessionRedis.getSessionRedis().getToken());
		
		sessionRedis.putInSessionRedis("city", city);

		log.info("从redis session取出存入的变量：" + sessionRedis.getFromSessionRedis("city").toString());

		return ResultVoUtil.success(CodeMsgEnum.SESSION_SUCCESS, sessionRedis.getSessionRedis());
	}	
	
	// 测试redis分布锁
	@GetMapping("/helloRedisLock")
	public Object helloRedisLock(@RequestParam(required = true) Long secKillId, IRedisSession redisSession) {
		
		// 不同用户并发请求下单购买商品
		CodeMsgEnum codeMsgResult = secKillService.secKillProduct1(redisSession, secKillId);
		log.info("用户{}购买商品{},结果是{}",redisSession.getSessionRedis().getUser().getPhone(), secKillId, codeMsgResult.getMsg());
		
		return ResultVoUtil.success(codeMsgResult);
	}	
}
